package wh.guistuff;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import wh.Order;

public class SwingInitializations 
{
	// No need for more advanced structures than basic arrays to store column strings
	private static final String orderColumns[] = {"OrderID", "CustomerID", "ProductID", "Quantity"};
	private static final String warehouseColumns[] = {"ProductID", "Product", "Price", "InStock"};
	
	private FlowLayout rowLayout;
	
	// Making the next four objects static to prevent potentially thousands of copies (in order/worker rows), 
	// and instead having one copy for all row objects.
	private static Dimension rowLabelDim = new Dimension(270, 12);
	private static Dimension rowPanelDim = new Dimension(280, 135);
	private static Dimension buttonDim = new Dimension(170, 20);
	private static Color workrRowColor = new Color(248, 248, 255);
	
	private Font textFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
	private ImageIcon logoImg;
	
	private static SwingInitializations instance = null; // Singleton purpose
	
	// This HasMap stores rows (JPanels) for each order a worker is working on.
	// As workers process orders, the worker rows needs to be updated to reflect that it is being processed, 
	// and which states are being changed (display progress in processing).
	// I decided on HashMap with orderID as key to retrieve corresponding JPanel; since the orderIDs are unique 
	// and thus suitable.
	// private HashMap<String, JPanel> rowMap = new HashMap<String, JPanel>();
	
	// Collections.synchronizedMap() guarantees that each atomic operation you want to run on the map will be synchronized.
	// But it must be synchronized in a block, externally, which it is.
	// From documentation -> This Map is fail-fast: if the map is structurally modified at any time after the iterator is created, 
	// in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. 
	// Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, 
	// non-deterministic behavior at an undetermined time in the future.
	// This is suitable when considering a large scale order processing enterprise (a response to requirements).
	
	private static Map<String, JPanel> rowMap = 
			Collections.synchronizedMap(new HashMap<String, JPanel>());
	
	
	//////// Singleton part Begin //////////////
	
	protected SwingInitializations() {
	      // Exists only to defeat instantiation.
	}
	
	public static SwingInitializations getInstance() {
	
		if (instance == null)
		{
	         instance = new SwingInitializations();
	    }
	    return instance;
	}
	///////// Singleton part End ////////////////
	
	public void doBasicInit() {
		
		initReusableObjects();
	}
	
	private void initReusableObjects()
	{
		rowLayout = new FlowLayout();
		rowLayout.setAlignment(FlowLayout.LEFT);
		rowLayout.setHgap(4);
	}
	
	public JPanel getMasterContentLayout()
	{
		FlowLayout masterLayout = new FlowLayout();
		masterLayout.setAlignment(FlowLayout.LEFT);
		masterLayout.setHgap(14);
		masterLayout.setVgap(10);
		
		CenterPanel p = new CenterPanel(masterLayout);
		p.setPreferredSize(new Dimension(1240, 530));
		p.setBackground(Color.white);
		p.setBorder(BorderFactory.createLineBorder(Color.black));
		
		return p;
	}
	
	public JPanel getTopHeaderPanel()
	{
		logoImg = new ImageIcon("img/whLogo2.png");
		
		Dimension ns = new Dimension(1240, 74);
        HeadPanel topPanel = new HeadPanel();
        topPanel.setPreferredSize(ns);
        topPanel.setBackground(Color.white);
        topPanel.setBorder(BorderFactory.createLineBorder(Color.black));
		
		return topPanel;
	}
	
	// This is the left panel with a table of orders
	public JPanel getOrderPanel()
	{
		FlowLayout orderLayout = new FlowLayout();
		orderLayout.setAlignment(FlowLayout.CENTER);
		orderLayout.setVgap(4);
		
		OrderPanel orderPanel = new OrderPanel(orderLayout);
		orderPanel.setPreferredSize(new Dimension(410, 510));
		orderPanel.setBackground(Color.white);
		
		JLabel olbl = new JLabel("Orders");
		olbl.setFont(new Font("serif", Font.TRUETYPE_FONT, 26));
		
		orderPanel.add(olbl);
		
		return orderPanel;
	}
	
	public JPanel getWarehousePanel()
	{
		FlowLayout whLayout = new FlowLayout();
		whLayout.setAlignment(FlowLayout.CENTER);
		whLayout.setVgap(4);
		
		WarehousePanel whPanel = new WarehousePanel(whLayout);
		whPanel.setPreferredSize(new Dimension(410, 510));
		whPanel.setBackground(Color.white);
		
		JLabel whbl = new JLabel("Warehouse");
		whbl.setFont(new Font("serif", Font.TRUETYPE_FONT, 26));
		
		whPanel.add(whbl);
		
		return whPanel;
		
	}
	
	public MyTableDataModel getWarehouseTableModel()
	{
		MyTableDataModel table = new MyTableDataModel();
		
		for (int i = 0; i < warehouseColumns.length; i++) {
			table.addColumn(warehouseColumns[i]);
		}
		
		return table;
	}
	
	public JPanel getWorkersListView() // ListView container (JPanel) for worker/order rows (also JPanels)
	{
		JPanel listView = new JPanel();
		listView.setLayout(new BoxLayout(listView, BoxLayout.Y_AXIS));
		listView.setBackground(Color.white);
		listView.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
		
		FlowLayout fl = new FlowLayout();
		fl.setAlignment(FlowLayout.CENTER);
		
		JPanel labelPanel = new JPanel(fl);
		labelPanel.setBackground(Color.white);
		JLabel wlbl = new JLabel("Workers list");
		wlbl.setFont(new Font("serif", Font.TRUETYPE_FONT, 22));
		
		labelPanel.add(wlbl);
		
		listView.add(labelPanel);
		
		listView.setBorder(BorderFactory.createLineBorder(Color.black));
		
		return listView;
	}
	
	public JPanel getWorkerRow(int workerNr, Order order)
	{
		JPanel row = new JPanel(rowLayout);
		row.setPreferredSize(rowPanelDim);
		row.setBackground(workrRowColor);
		// row.setLayout(new BoxLayout(row, BoxLayout.Y_AXIS));
		// row.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
		row.setBorder(BorderFactory.createLineBorder(Color.black));
		
		
		JLabel workerLbl = new JLabel("Worker "+workerNr); // Index position 0 in JPanel
		JLabel orderLbl =    new JLabel("On order:               "+order.getOrderID()); // Index position 1 in JPanel
		JLabel customerLbl = new JLabel("On customer:       "+order.getCustomerID()); // Index position 2 in JPanel
		JLabel cTypeLbl = new JLabel("Customer type:    ");
		JLabel costLbl = new JLabel("Total cost:             ");
		JLabel statusLbl = new JLabel("Status:                    ");
		JButton stopButton = new JButton("Cancel order");
		
		workerLbl.setPreferredSize(rowLabelDim);
		orderLbl.setPreferredSize(rowLabelDim);
		customerLbl.setPreferredSize(rowLabelDim);
		cTypeLbl.setPreferredSize(rowLabelDim);
		costLbl.setPreferredSize(rowLabelDim);
		statusLbl.setPreferredSize(rowLabelDim);
		stopButton.setPreferredSize(buttonDim);
		
		orderLbl.setFont(textFont);
		customerLbl.setFont(textFont);
		cTypeLbl.setFont(textFont);
		costLbl.setFont(textFont);
		statusLbl.setFont(textFont);
		stopButton.setFont(textFont);
		
		row.add(workerLbl);
		row.add(orderLbl);
		row.add(customerLbl);
		row.add(cTypeLbl);
		row.add(costLbl);
		row.add(statusLbl);
		row.add(stopButton);
		
		rowMap.put(order.getOrderID(), row); // Using orderID as unique key to worker panel. Each worker is working on one order
		
		return row;
		
	}
	
	
	public synchronized JPanel getRowPanel(String orderID)
	{
		if (rowMap.containsKey(orderID))
			return rowMap.get(orderID);
		else
			System.out.println("rowMap does not have orderID!!! Size: "+rowMap.size());
		
		return null;
	}
	
	public MyTableDataModel getOrderTableModel()
	{
		MyTableDataModel table = new MyTableDataModel();
		
		for (int i = 0; i < orderColumns.length; i++) {
			table.addColumn(orderColumns[i]);
		}
		
		return table;
	}
	
	private class CenterPanel extends JPanel {
		
		public CenterPanel(LayoutManager layout) {
			super(layout);
		}
        public void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            // new Color(176, 196, 222) light blue
            GradientPaint gradient = new GradientPaint(0, 0, Color.white, 1240, 660, new Color(240, 248, 255));
            g2d.setPaint(gradient);
            g2d.fillRect(0, 0, 1240, 660);
        }
    }
	
	private class WarehousePanel extends JPanel {
		
		public WarehousePanel(LayoutManager layout) {
			super(layout);
		}
        public void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            // new Color(176, 196, 222) light blue
            GradientPaint gradient = new GradientPaint(0, 0, Color.white, 450, 470, new Color(176, 196, 222));
            g2d.setPaint(gradient);
            g2d.fillRect(0, 0, 450, 470);
        }
    }

	private class OrderPanel extends JPanel {
	
		public OrderPanel(LayoutManager layout) {
			super(layout);
		}
		public void paintComponent(Graphics g) {
			Graphics2D g2d = (Graphics2D) g;
			// new Color(176, 196, 222) light blue
			GradientPaint gradient = new GradientPaint(0, 0, Color.white, 450, 470, new Color(176, 196, 222));
			g2d.setPaint(gradient);
			g2d.fillRect(0, 0, 450, 470);
		}
	}
	
	private class HeadPanel extends JPanel {
		
        public void paintComponent(Graphics g) {
        	
        	Graphics2D g2d = (Graphics2D) g;
        	GradientPaint gradient = new GradientPaint(0, 0, Color.white, 1240, 100, new Color(255, 250, 250));
            g2d.setPaint(gradient);
            g2d.fillRect(0, 0, 1240, 100);
            g2d.drawImage(logoImg.getImage(), 440, 0, this);
        }
    }
}
